﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Net;
using Amazon;
using Amazon.Runtime;
using Amazon.S3;
using Amazon.S3.Model;
using Newtonsoft.Json;
using Rezene.Web.Business.Amazon.Entities;

namespace Rezene.Web.Business.Amazon
{
    public class AmazonRepository : IAmazonRepository
    {
        private IAmazonS3 s3Client { get; set; }
        private string s3Bucket { get; set; }
        private const string GalleryInfoFileName = "rezene";
        private string[] allowedExtensions;

        public IAmazonFactory AmazonFactory { get; set; }            

        public AmazonRepository()
        {
            allowedExtensions = new string[0];
        }

        public AmazonRepository(IAmazonFactory factory)
        {
            AmazonFactory = factory;
            allowedExtensions = new string[0];
        }


        public string AllowedExtensions
        {
            get { return string.Join(",", allowedExtensions); }
            set { allowedExtensions = value.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries); }
        }

        private string EnsurePathIsValid(string path)
        {
            return string.IsNullOrEmpty(path) ? path : path.EndsWith("/") ? path : path + "/";
        }

        private bool UploadFile(string localFile, string remoteFile)
        {
            var request = new PutObjectRequest()
            {
                BucketName = s3Bucket,
                Key = remoteFile,
                FilePath = localFile
            };
            var response = s3Client.PutObject(request);
            return response.HttpStatusCode == HttpStatusCode.OK;
        }

        private bool SaveAmazonObjectInfo(S3BaseObject obj)
        {
            return SaveAmazonObjectInfo(obj, string.Empty);
        }

        private bool SaveAmazonObjectInfo(S3BaseObject obj, string prependText)
        {
            var tempFilePath = Path.GetTempPath() + Guid.NewGuid().ToString() + ".json";
            File.WriteAllText(tempFilePath, JsonConvert.SerializeObject(obj));
            return UploadFile(tempFilePath, (string.IsNullOrEmpty(prependText)?obj.AmazonPath:EnsurePathIsValid(obj.AmazonPath)) + prependText + ".json");
        }

        private bool FileExists(string path)
        {
            try
            {
                var request = new GetObjectRequest()
                {
                    BucketName = s3Bucket,
                    Key = path
                };
                using (var response = s3Client.GetObject(request))
                {
                }
                return true;
            }
            catch (Exception)
            {
                return false;                
            }
        }

        private T GetAmazonObjectInfo<T>(string path)
        {
            var request = new GetObjectRequest()
            {
                BucketName = s3Bucket,
                Key = path
            };
            
            using (var response = s3Client.GetObject(request))
            {
                var tempFilePath = Path.GetTempPath() + Guid.NewGuid().ToString() + ".json";
                response.WriteResponseStreamToFile(tempFilePath);
                var jsonString = File.ReadAllText(tempFilePath);
                return JsonConvert.DeserializeObject<T>(jsonString);
            }
        }

        public bool Init(string amazonAccessKey, string amazonSecretKey, RegionEndpoint regionEndpoint, string bucketName)
        {
            s3Client = new AmazonS3Client(new BasicAWSCredentials(amazonAccessKey,amazonSecretKey), regionEndpoint);
            s3Bucket = bucketName;
            return s3Client != null;
        }

        public bool IsInitialized()
        {
            return s3Client != null;
        }

        public IList<S3Gallery> GetGalleries(string folder)
        {
            folder = EnsurePathIsValid(folder);
            var request = new ListObjectsRequest
            {
                BucketName = s3Bucket,
                MaxKeys = 100,
                Prefix = folder,
                Delimiter = "/"
            };
            var galleries = new List<S3Gallery>();
            do
            {
                var response = s3Client.ListObjects(request);
                if (response.CommonPrefixes.Any())
                {
                    foreach(var prefix in response.CommonPrefixes.Where(p => p != "/" && !allowedExtensions.Contains(Path.GetExtension(p))))
                    {
                        galleries.Add(GetGalleryInfo(prefix));
                    }
                    /*
                    galleries.AddRange(response.CommonPrefixes.Where(p => p != "/").Select(prefix => new S3Gallery()
                    {
                        Name = prefix
                    }));
                    */
                }

                if (response.IsTruncated)
                {
                    request.Marker = response.NextMarker;
                }
                else
                {
                    request = null;
                }
                
            } while (request != null);

            return galleries;
        }
        
        public bool SavePhotoInfo(S3PhotoObject photoObject)
        {            
            return SaveAmazonObjectInfo(photoObject);
        }

        public bool SaveGalleryInfo(S3Gallery gallery)
        {            
            return SaveAmazonObjectInfo(gallery, GalleryInfoFileName);
        }

        public S3Gallery GetGalleryInfo(string galleryPath)
        {
            try
            {

                var infoFilePath = EnsurePathIsValid(galleryPath) + GalleryInfoFileName + ".json";
                if (!FileExists(infoFilePath))
                {
                    var gallery = new S3Gallery(AmazonFactory.CreateDefaultObjectFromPath(s3Bucket, galleryPath));
                    gallery.Show = true;
                    SaveGalleryInfo(gallery);
                }
                return GetAmazonObjectInfo<S3Gallery>(infoFilePath);
            }catch(Exception ex)
            {
                return null;
            }
        }

        public IList<S3PhotoObject> GetPhotos(string galeryPath)
        {
            var path = EnsurePathIsValid(galeryPath);
            var request = new ListObjectsRequest
            {
                BucketName = s3Bucket,
                MaxKeys = 100,
                Prefix = path,
                Delimiter = "/"
            };
            var photos = new List<S3PhotoObject>();
            do
            {
                var response = s3Client.ListObjects(request);
                if (response.S3Objects.Any())
                {
                    foreach (var obj in response.S3Objects.Where(c => c.Size > 0 && allowedExtensions.Contains(Path.GetExtension(c.Key))))
                    {
                        //var photoObj = AmazonFactory.CreatePhotoObject(s3Bucket, obj.Key.Replace(galeryPath, "").Replace("/", ""), galeryPath, "", "");
                        var photoObj = GetPhotoInfo(obj.Key);
                        photos.Add(photoObj);
                    }                   
                }

                if (response.IsTruncated)
                {
                    request.Marker = response.NextMarker;
                }
                else
                {
                    request = null;
                }

            } while (request != null);
            return photos;
        }

        public S3PhotoObject GetPhotoInfo(string photoPath)
        {
            if (!FileExists(photoPath + ".json"))
            {
                var photoObj = new S3PhotoObject(AmazonFactory.CreateDefaultObjectFromPath(s3Bucket, photoPath));
                SavePhotoInfo(photoObj);
            }
            return GetAmazonObjectInfo<S3PhotoObject>(photoPath+".json");
        }
    }
}